# ~*~ coding: utf-8 ~*~
import os
from datetime import timedelta

from redbeat import RedBeatSchedulerEntry
from celery import schedules
from flask import current_app

from apps.extensions import celery
from apps.common.utils import datetime_obj_to_str


def get_celery_task_log_path(task_id):
    rel_path = os.path.join(task_id[0], task_id[1], task_id + '.log')
    path = os.path.join(current_app.config.get('CELERY_LOG_DIR'), rel_path)
    os.makedirs(os.path.dirname(path), exist_ok=True)
    return path


def create_or_update_celery_periodic_task(task):
    """
    :param task: {
        'add-every-monday-morning': {
            'task': 'tasks.add' # A registered celery task,
            'interval': 30,
            'crontab': "30 7 * * *",
            'args': (16, 16),
            'kwargs': {},
            'enabled': False,
        },
    }
    :return:
    """
    current_app.logger.info('Redid beat task: {}'.format(task))
    for name, detail in task.items():

        schedule = None
        if detail['crontab'] is None and detail['interval'] is not None:
            if not isinstance(detail['interval'], schedules.schedule):
                schedule = schedules.schedule(
                    run_every=timedelta(seconds=detail['interval'])
                )
            else:
                schedule = detail['interval']

        if detail['crontab'] is not None and detail['interval'] is None:
            if not isinstance(detail['crontab'], schedules.crontab):
                minute = detail['crontab'].split()[0]
                hour = detail['crontab'].split()[1]
                day_of_month = detail['crontab'].split()[2]
                month_of_year = detail['crontab'].split()[3]
                day_of_week = detail['crontab'].split()[4]
                schedule = schedules.crontab(
                    minute=minute,
                    hour=hour,
                    day_of_week=day_of_week,
                    day_of_month=day_of_month,
                    month_of_year=month_of_year,
                )
            else:
                schedule = detail['crontab']

        entry = RedBeatSchedulerEntry(
            name=name,
            task=detail['task'],
            schedule=schedule,
            args=detail['args'],
            kwargs=detail['kwargs'],
            enabled=detail['enabled'],
            app=celery
        )
        entry.save()


def delete_celery_periodic_task(task_name):
    entry = RedBeatSchedulerEntry(name=task_name, app=celery)
    entry.delete()


def get_celery_periodic_task(task_name):
    """
    127.0.0.1:6379[8]> hget beat:task-ops-add-test-6-6 definition
    127.0.0.1:6379[8]> hget beat:task-ops-add-test-6-6 meta

    127.0.0.1:6379[8]> zrange beat::schedule 0 -1
    :param task_name:
    :return:
    """
    task_run_info = {}
    entry = RedBeatSchedulerEntry(name=task_name, app=celery)

    definition = RedBeatSchedulerEntry.load_definition(entry.key, app=celery)
    task_run_info.update(definition)

    meta = RedBeatSchedulerEntry.load_meta(entry.key, app=celery)
    task_run_info.update(meta)

    if isinstance(task_run_info.get('schedule'), schedules.crontab):
        task_run_info['schedule'] = ' '.join(task_run_info.get('schedule').__reduce__()[1])
        task_run_info['last_run_at'] = datetime_obj_to_str(task_run_info.get('last_run_at'))
    elif isinstance(task_run_info.get('schedule'), schedules.schedule):
        task_run_info['schedule'] = task_run_info.get('schedule').run_every.seconds
        task_run_info['last_run_at'] = datetime_obj_to_str(task_run_info.get('last_run_at'))
    return task_run_info
